package org.sbbs.base.jpa.manager.impl;

import java.io.Serializable;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;

import org.sbbs.base.jpa.dao.BaseRepo;
import org.sbbs.base.jpa.entity.BaseEntity;
import org.sbbs.base.jpa.manager.BaseManager;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.history.Revision;
import org.springframework.data.history.Revisions;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.repository.query.FluentQuery;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

/**
 * @param <T>
 * @param <ID>
 * @param <R>
 * @author jenkins Manager体系原则上是负责实体数据管理功能
 */
@Transactional(readOnly = false, rollbackFor = Throwable.class)
public class BaseManagerImpl<T extends BaseEntity, ID extends Serializable, R extends BaseRepo<T, ID>> implements BaseManager<T, ID, R> {

    private BaseRepo<T, ID> repo;

    public void setRepo(BaseRepo<T, ID> rep) {
        this.repo = rep;
    }

    public T findById(ID id) {
        Optional<T> rs = this.repo.findById(id);
        if (rs.isPresent()) {

            return rs.get();
        } else {
            return null;
        }
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public T save(T entity) {
        return repo.save(entity);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    @SuppressWarnings("unchecked")
    public boolean remove(T entity) {
        return this.removeById((ID) entity.getId());
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public boolean removeById(ID id) {
        Optional<T> rs = this.repo.findById(id);
        if (rs.isPresent()) {
            this.repo.deleteById(id);
            return true;
        } else {
            this.repo.deleteById(id);
            return false;
        }
    }

    /**
     * Get a list of all the objects of the specified type.
     */
    @Override
    public List<T> findAll() {
        return repo.findAll();
    }

    @Override
    public List<T> findAllById(Iterable<ID> ids) {
        return this.repo.findAllById(ids);
    }

    @Override
    public List<T> findAll(Sort sort) {
        return this.repo.findAll(sort);
    }

    @Override
    public boolean existsById(ID id) {
        return repo.existsById(id);
    }

    @Override
    public long count() {
        return this.repo.count();
    }

    @Override
    public void deleteById(ID id) {
        this.repo.deleteById(id);
    }

    @Override
    public void delete(T entity) {
        this.repo.delete(entity);
    }

    @Override
    public void deleteAllById(Iterable<? extends ID> ids) {
        this.repo.deleteAllById(ids);
    }

    @Override
    public void deleteAll(Iterable<? extends T> entities) {
        this.repo.deleteAll(entities);
    }

    @Override
    public void deleteAll() {
        this.repo.deleteAll();
    }

    @Override
    public <S extends T> List<S> saveAll(Iterable<S> entities) {
        return this.repo.saveAll(entities);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void removeAll(List<T> list) {
        repo.deleteAll(list);

    }

    @Override
    public Page<T> findAll(Pageable pageable) {
        return repo.findAll(pageable);
    }

    @Override
    public Optional<T> findOne(Specification<T> spec) {
        return this.repo.findOne(spec);
    }

    @Override
    public List<T> findAll(Specification<T> spec) {
        return this.repo.findAll(spec);
    }

    @Override
    public Page<T> findAll(Specification<T> spec, Pageable pageable) {
        return this.repo.findAll(spec, pageable);
    }

    @Override
    public List<T> findAll(Specification<T> spec, Sort sort) {
        return this.repo.findAll(spec, sort);
    }

    @Override
    public long count(Specification<T> spec) {
        return this.repo.count(spec);
    }

    @Override
    public boolean exists(Specification<T> spec) {
        return this.repo.exists(spec);
    }

    @Override
    public long delete(Specification<T> spec) {
        return repo.delete(spec);
    }

    @Override
    public <S extends T, R1> R1 findBy(Specification<T> spec, Function<FluentQuery.FetchableFluentQuery<S>, R1> queryFunction) {
        return repo.findBy(spec, queryFunction);
    }

    @Override
    public <S extends T> Optional<S> findOne(Example<S> example) {
        return repo.findOne(example);
    }

    @Override
    public <S extends T> Page<S> findAll(Example<S> example, Pageable pageable) {
        return repo.findAll(example, pageable);
    }

    @Override
    public <S extends T> long count(Example<S> example) {
        return repo.count(example);
    }

    @Override
    public <S extends T> boolean exists(Example<S> example) {
        return repo.exists(example);
    }

    @Override
    public <S extends T, R1> R1 findBy(Example<S> example, Function<FluentQuery.FetchableFluentQuery<S>, R1> queryFunction) {
        return repo.findBy(example, queryFunction);
    }

    @Override
    public List<T> findAllById(List<ID> ids) {
        return repo.findAllById(ids);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public List<T> saveAll(List<T> entities) {
        return repo.saveAll(entities);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void removeAllById(List<? extends ID> ids) {
        repo.deleteAllById(ids);
    }
//

    @Override
    public Page<Long> findAllIds(Pageable pageable) {
        return repo.findAllIds(pageable);
    }

    @Override
    public void flush() {
        this.repo.flush();
    }

    @Override
    public <S extends T> S saveAndFlush(S entity) {
        return this.repo.saveAndFlush(entity);
    }

    @Override
    public <S extends T> List<S> saveAllAndFlush(Iterable<S> entities) {
        return this.repo.saveAllAndFlush(entities);
    }

    @Override
    public void deleteAllInBatch(Iterable<T> entities) {
        this.repo.deleteAllInBatch(entities);
    }

    @Override
    public void deleteAllByIdInBatch(Iterable<ID> ids) {
        this.repo.deleteAllByIdInBatch(ids);
    }

    @Override
    public void deleteAllInBatch() {
        this.repo.deleteAllInBatch();
    }

    @Override
    public T getOne(ID id) {
        return this.repo.getOne(id);
    }

    @Override
    public T getById(ID id) {
        return this.repo.getById(id);
    }

    @Override
    public T getReferenceById(ID id) {
        return this.repo.getReferenceById(id);
    }

    @Override
    public <S extends T> List<S> findAll(Example<S> example) {
        return this.repo.findAll(example);
    }

    @Override
    public <S extends T> List<S> findAll(Example<S> example, Sort sort) {
        return this.repo.findAll(example, sort);
    }

    @Override
    public BaseRepo<T, ID> getRepo() {
        return this.repo;
    }

    //    @Override
    public Optional<Revision<Long, T>> findLastChangeRevision(ID id) {
        return this.repo.findLastChangeRevision(id);
    }

    //    @Override
    public Revisions<Long, T> findRevisions(ID id) {
        return this.repo.findRevisions(id);
    }

    //    @Override
    public Page<Revision<Long, T>> findRevisions(ID id, Pageable pageable) {
        return this.repo.findRevisions(id, pageable);
    }

    //    @Override
    public Optional<Revision<Long, T>> findRevision(ID id, Long revisionNumber) {
        return this.repo.findRevision(id, revisionNumber);
    }
}
